/**
 *   调用蓝牙 
 */
class Bluetooth {
	constructor(options) {
		this.options = {
			serviceId: '', // 主服务id
			notifyCharacteristicsId: '', // 通知特征值
			writeCharacteristicsId: '', // 写入特征值
			readCharacteristicsId: '', // 读取特征值
			deviceId: '', // 设备唯一id
			start: () => {

			},
			ready: () => {

			},
			errHandler: () => {
				wx.showModal({
					title: '提示',
					content: '连接失败,请关闭蓝牙重新打开尝试'
				})
			}
		} // 搜索设备参数
		this.params = {
			enable: wx.canIUse('openBluetoothAdapter'), // 兼容处理
			isIos: false // 是否是ios,安卓下可以直接连mac地址  ios需要解密广播数据来进行蓝牙过滤
		}
		this.options = Object.assign({}, this.options, options)
		this.deviceId = '' // 设备deviceId
		this.isFirstSend = true // 分包情况下 是否是一次发送数据
		this.end = false // 分包是否完成
		this.search_timer = null // 搜索定时器
		this.maxSearchTimes = 10 // 最大搜索次数
		this.currentSearchTimes = 0 // 当前搜索的次数
		this.isConnect = false
	}
	init() {
		const {
			system
		} = wx.getSystemInfoSync()
		this.params.isIos = system.indexOf('iOS') > -1
		if (!this.params.enable) {
			wx.showModal({
				title: '提示',
				content: '当前微信版本过低，不支持蓝牙功能，请升级到最新微信版本后重试。'
			})
			this.options.fail()
		} else {
			// 打开蓝牙适配器
			wx.openBluetoothAdapter({
				success: res => {
					console.log('====================================');
					console.log(`初始化蓝牙模块成功`);
					console.log('====================================');
					this.connect()
				},
				fail: err => {
					wx.hideLoading()
					wx.showToast({
						title: '请检查蓝牙开关是否打开',
						icon: 'none'
					})
					this.options.fail()
					console.log('====================================');
					console.log(`初始化蓝牙模块失败`, err);
					console.log('====================================');
				}
			})
		}
	}
	// 连接模块
	connect() {
		if (this.search_timer) {
			clearInterval(this.search_timer)
			this.search_timer = null
		}
		wx.getBluetoothAdapterState({
			success: ({
				available
			}) => {
				console.log('====================================');
				console.log(`蓝牙适配器状态${available ? '已经' : '没有'}打开`);
				console.log('====================================');
				if (available) {
					// if (this.options.serviceId) {
					// 	// 先检查目标设备已被连接
					// 	wx.getConnectedBluetoothDevices({
					// 		services: [this.options.serviceId],
					// 		success: ({
					// 			devices
					// 		}) => {
					// 			console.log('====================================');
					// 			console.log(`${devices.length ? '有' : '没有'}已连接设备`);
					// 			console.log('====================================');
					// 			if (devices.length) {
					// 				this.deviceId = devices[0].deviceId
					// 				this.getServices()
					// 			} else {
					// 				wx.startBluetoothDevicesDiscovery({
					// 					allowDuplicatesKey: false,
					// 					services: [],
					// 					success: res => {
					// 						this.startSearch()
					// 					}
					// 				})
					// 			}
					// 		},
					// 		fail(e) {
					// 				console.log(66,e);
					// 		}
					// 	})
					// } else {
						wx.startBluetoothDevicesDiscovery({
							allowDuplicatesKey: false,
							services: [],
							success: res => {
								this.startSearch()
							}
						})
					// }

				}
			},
			fail: err => {
				wx.hideLoading()
				wx.showToast({
					title: '请检查蓝牙开关是否打开',
					icon: 'none'
				})
				this.options.fail()
			}
		})
	}

	// 搜索模块
	startSearch(callback) {
		if (this.currentSearchTimes >= this.maxSearchTimes) {
			clearInterval(this.search_timer)
			this.search_timer = null
			this.currentSearchTimes = 0
			wx.showToast({
				title: '没有找到符合的蓝牙设备',
				icon: 'none'
			})
			this.options.fail()
			return
		}
		this.currentSearchTimes++
		wx.getBluetoothDevices({
			success: ({
				devices
			}) => {
				let len = devices.length
				for (let i = 0; i < len; i++) {
					console.log('附近蓝牙数据', devices[i]);
					if (this.options.deviceId == devices[i].deviceId && !this.isConnect) {
						console.log('====================================');
						console.log(`找到符合的蓝牙：${devices[i].name}`);
						console.log('====================================');
						this.isConnect = true
						this.deviceId = devices[i].deviceId
						clearTimeout(this.search_timer)
						this.search_timer = null
						wx.stopBluetoothDevicesDiscovery({
							success: res => {
								console.log('====================================');
								console.log(`停止设备搜索`);
								console.log('====================================');
								this.connection()
							}
						});
					}
				}
				if (!this.isConnect) {
					this.search_timer = setTimeout(() => {
						this.startSearch()
					}, 1200);
				}
			},
			fail(res) {
				wx.hideLoading()
				wx.showModal({
					title: '提示',
					content: '请打开手机定位后再次操作',
					success: function(res) {}
				});

			}
		})
	}
	// 建立连接
	connection() {
		wx.createBLEConnection({
			deviceId: this.deviceId,
			success: res => {
				console.log('====================================');
				console.log(`连接目标设备成功`);
				console.log('====================================');
				this.getServices()
			},
			fail: err => {
				this.failBack(err)
			}
		})
	}
	// 获取服务列表找寻主服务uuid
	getServices() {
		wx.getBLEDeviceServices({
			deviceId: this.deviceId,
			success: ({
				services
			}) => {
				console.log('====================================');
				console.log(`获取到的服务列表：`, services);
				console.log('====================================');
				let len = services.length
				let findService = false
				for (let i = 0; i < len; i++) {
					if (services[i].uuid == this.options.serviceId) {
						this.options.serviceId = services[i].uuid
						findService = true
						console.log('====================================');
						console.log('找到主服务uuid为：', services[i].uuid);
						console.log('====================================');
						break
					}
				}
				if (findService) {
					this.getCharacteristics()
				} else {
					wx.showToast({
						title: '没有找到对应服务',
						icon: 'none'
					})
					this.options.fail()
				}
				wx.hideLoading()
			},
			fail: err => {
				this.failBack(err)
			}
		})
	}
	// 获取写，通知服务uuid，以及特征值
	getCharacteristics() {
		wx.getBLEDeviceCharacteristics({
			deviceId: this.deviceId,
			serviceId: this.options.serviceId,
			success: ({
				characteristics
			}) => {
				let len = characteristics.length;
				for (var i = 0; i < len; i++) {
					if (this.options.notifyCharacteristicsId && this.options.writeCharacteristicsId) {
						break
					}
					if (characteristics[i].properties.notify) {
						this.options.notifyCharacteristicsId = characteristics[i].uuid;
						console.log('====================================');
						console.log(`通知特征值uuid:`, characteristics[i].uuid);
						console.log('====================================');
					}
					if (characteristics[i].properties.write) {
						this.options.writeCharacteristicsId = characteristics[i].uuid
						console.log('====================================');
						console.log(`写入特征值uuid:`, characteristics[i].uuid);
						console.log('====================================');
					}
				}
				this.openNotify()
			},
			fail: err => {
				console.log('寻找特征值失败');
				this.failBack(err)
			}
		})
	}
	// 开启notify
	openNotify() {
		wx.notifyBLECharacteristicValueChange({
			deviceId: this.deviceId,
			serviceId: this.options.serviceId,
			characteristicId: this.options.notifyCharacteristicsId,
			state: true,
			success: res => {
				console.log('====================================');
				console.log('开启notify成功');
				console.log('====================================');
				this.options.ready()
			},
			fail: err => {
				console.log('开启notify失败', err);
				this.failBack(err)
			}
		})
	}
	// 发送指令
	sendData(data, callback) {
		// 监听特征值变化，写入数据后，会在这里拿到蓝牙回给我们的数据
		wx.onBLECharacteristicValueChange(({
			value
		}) => {
			let response = this.buf2hex(value)
			console.log('====================================');
			console.log('蓝牙回应解密后的数据：-------->', response);
			console.log('====================================');
			callback && callback(response)
		})
		this.send(data)
	}
	// 分包发送
	sendBySlice(data, callback) {
		console.log('发送的原始数据', data);
		if (this.isFirstSend) {
			this._data = data
			this.isFirstSend = false
		}
		let len = (data.length / 2) //  发送的指令长度
		// 如果指令大于20个字节，截取前20个字节发送
		if (len > 20) {
			let sliceStr = data.substr(0, 40) // 本次发送数据
			let lastStr = data.substr(40) // 剩下的数据
			let buffer = new ArrayBuffer(20)
			let dataView = new DataView(buffer);
			for (var i = 0; i < sliceStr.length / 2; i++) {
				dataView.setUint8(i, '0x' + sliceStr.substr(i * 2, 2));
			}
			wx.writeBLECharacteristicValue({
				deviceId: this.deviceId,
				serviceId: this.options.serviceId,
				characteristicId: this.options.writeCharacteristicsId,
				value: buffer,
				success: res => {
					console.log('写入数据成功');
					this.sendData(lastStr, callback)
				},
				fail: err => {
					console.log('写入失败');
					console.log(err);
					console.log('开始重新发送');
					// 写入失败后重新发送数据包
					this.isFirstSend = true
					this.sendData(this._data, callback)
				}
			})
		} else {
			let buffer = new ArrayBuffer(len)
			let dataView = new DataView(buffer);
			for (var i = 0; i < data.length / 2; i++) {
				dataView.setUint8(i, '0x' + data.substr(i * 2, 2));
			}
			wx.writeBLECharacteristicValue({
				deviceId: this.deviceId,
				serviceId: this.options.serviceId,
				characteristicId: this.options.writeCharacteristicsId,
				value: buffer,
				success: res => {
					console.log('写入数据成功');
					this._data = null
					this.isFirstSend = true
					this.end = true
				},
				fail: err => {
					console.log('写入失败');
					console.log(err);
					console.log('开始重新发送');
					// 写入失败后重新发送数据包
					this.isFirstSend = true
					this.sendData(this._data, callback)
				}
			})
		}
	}
	// 不分包发送
	send(data) {
		console.log('====================================');
		console.log('发送的原始数据', data);
		console.log('====================================');
		var typedArray = new Uint8Array(data.match(/[\da-f]{2}/gi).map(function(h) {
			return parseInt(h, 16)
		}))
		wx.writeBLECharacteristicValue({
			deviceId: this.deviceId,
			serviceId: this.options.serviceId,
			characteristicId: this.options.writeCharacteristicsId,
			value: typedArray.buffer,
			success: res => {
				console.log('====================================');
				console.log('写入数据成功');
				console.log('====================================');
			},
			fail: err => {
				console.log('====================================');
				console.log('写入失败', err);
				console.log('====================================');
				this.options.fail && this.options.fail(err)
				this.failBack(err)
			}
		})
	}
	// arraubuffer 转 字符串
	buf2hex(buffer) {
		return Array.prototype.map.call(new Uint8Array(buffer), x => ('00' + x.toString(16)).slice(-2)).join('');
	}
	failBack(err) {
		wx.hideLoading()
		this.close(() => {
			this.init()
		})
		let {
			errCode
		} = err
		if (errCode == 10003 || errCode == 10008) {

		}
		//this.options.errHandler(err)
	}
	assign(options) {
		this.options = Object.assign({}, this.options, options)
		let a = JSON.stringify(this.options)
		console.log('options', a);
		return this
	}
	close(callback) {
		this.currentSearchTimes = 0
		this.isConnect = false
		this.options.deviceId = ''
		if (this.deviceId) {
			wx.closeBLEConnection({
				deviceId: this.deviceId,
				complete: () => {
					wx.closeBluetoothAdapter({
						success: () => {
							this.deviceId = ''
							callback && callback()
							console.log('====================================');
							console.log('断开连接成功')
							console.log('====================================');
						}
					})
				}
			})
		} else {
			wx.closeBluetoothAdapter({
				success: () => {
					callback && callback()
					console.log('====================================');
					console.log('断开连接成功')
					console.log('====================================');
				},
				fail: err => {
					console.log('====================================');
					console.log(err);
					console.log('断开连接失败');
					console.log('====================================');
				}
			})

		}

	}
}

export default new Bluetooth()
